<?php

namespace App\Services\JuheH5;

use App\Models\Games;
use App\Models\UserAccount;
use App\Services\GameChannelService;
use App\Services\Idcard\IdcardAuthService;
use App\Services\PhoneCodeService;
use App\Services\SdkService;
use App\Services\ServiceBase;
use Illuminate\Support\Facades\Crypt;
use YQ\YqExtend;

class AccountService extends ServiceBase
{
    // 校验当前是否开放注册
    public function canReg($game_id)
    {
        $game = Games::where('game_id', $game_id)->first();
        if ($game && $game->can_reg != 1) {
            return false;
        }

        return true;
    }

    /**
     * 快速注册
     */
    public function fastReg($game_id = 0)
    {
        $can_reg = $this->canReg($game_id);
        if (!$can_reg) {
            return 6054;
        }

        // 账号可能出现重复，此处进行最多3次重试
        $check_num = 1;
        while ($check_num <= 3) {
            $check_num++;
            try {
                $account  = YqExtend::getRandomInt(10);
                $password = YqExtend::getRandom(6);

                $class                  = new UserAccount;
                $class->account         = $account;
                $class->password        = Crypt::encryptString($password);
                $class->openid          = YqExtend::uniqid32();
                $class->ip              = YqExtend::getIP();
                $class->create_time     = time();
                $class->last_login_time = time();

                $res = $class->save();
                if ($res) {
                    $class            = UserAccount::where('account', $class->account)->first();
                    $data             = $this->dataHandler($class->toArray());
                    $data['password'] = $password;
                    return $data;
                }
            } catch (\Throwable $th) {
                yqlog($th->getMessage());
            }
        }

        return -1;
    }

    /**
     * 手机号码注册
     */
    public function phoneReg($params)
    {
        $game_id = $params['game_id'];
        $can_reg = $this->canReg($game_id);
        if (!$can_reg) {
            return 6054;
        }

        if (!$this->phoneVerify($params['phone'] ?? '')) {
            return 7004;
        }

        $verify = $this->codeVerify(PhoneCodeService::PHONE_CODE_TYPE_REG, $params['phone'], $params['code'] ?? '');
        if ($verify !== true) {
            return $verify;
        }

        if (!$this->passwordVerify($params['password'] ?? '')) {
            return 7002;
        }

        if ($this->isAccountExisted($params['phone'])) {
            return 7003;
        }

        if ($this->isPhoneExisted($params['phone'])) {
            return 7012;
        }

        try {
            $class                  = new UserAccount;
            $class->account         = $params['phone'];
            $class->password        = Crypt::encryptString($params['password']);
            $class->openid          = YqExtend::uniqid32();
            $class->ip              = YqExtend::getIP();
            $class->phone           = $params['phone'];
            $class->phone_bind_time = time();
            $class->create_time     = time();
            $class->last_login_time = time();

            $res = $class->save();
            if ($res) {
                $class = UserAccount::where('account', $class->account)->first();
                return $this->dataHandler($class->toArray());
            }
        } catch (\Throwable $th) {
            yqlog($th->getMessage());
            return 9999;
        }

        return -1;
    }

    /**
     * 账号注册
     */
    public function accountReg($params)
    {
        $game_id = $params['game_id'];
        $can_reg = $this->canReg($game_id);
        if (!$can_reg) {
            return 6054;
        }

        if (!$this->accountVerify($params['account'] ?? '')) {
            return 7001;
        }

        if (!$this->passwordVerify($params['password'] ?? '')) {
            return 7002;
        }

        if ($this->isAccountExisted($params['account'])) {
            return 7003;
        }

        try {
            $class                  = new UserAccount;
            $class->account         = $params['account'];
            $class->password        = Crypt::encryptString($params['password']);
            $class->openid          = YqExtend::uniqid32();
            $class->ip              = YqExtend::getIP();
            $class->create_time     = time();
            $class->last_login_time = time();

            $res = $class->save();
            if ($res) {
                $class = UserAccount::where('account', $class->account)->first();
                return $this->dataHandler($class->toArray());
            }
        } catch (\Throwable $th) {
            yqlog($th->getMessage());
            return 9999;
        }

        return -1;
    }

    /**
     * 手机登录
     */
    public function phoneLogin($params)
    {
        if (!$this->phoneVerify($params['phone'] ?? '')) {
            return 7004;
        }

        $verify = $this->codeVerify(PhoneCodeService::PHONE_CODE_TYPE_LOGIN, $params['phone'], $params['code'] ?? '');
        if ($verify !== true) {
            return $verify;
        }

        if (!$this->isPhoneExisted($params['phone'])) {
            return 7013;
        }

        try {
            $class                  = UserAccount::where('phone', $params['phone'])->first();
            $class->last_login_time = time();

            $res = $class->save();
            if ($res) {
                return $this->dataHandler($class->toArray(), $params['game_id'] ?? 0);
            }
        } catch (\Throwable $th) {
            yqlog($th->getMessage());
            return 9999;
        }

        return -1;
    }

    public function getByAccountOrPhone($account)
    {
        $class = UserAccount::where('account', $account)->first();
        if (!$class) {
            $class = UserAccount::where('phone', $account)->first();
        }

        return $class;
    }

    /**
     * 账号登录
     */
    public function accountLogin($params)
    {
        if (!$this->accountVerify($params['account'] ?? '')) {
            return 7001;
        }

        if (!$this->passwordVerify($params['password'] ?? '')) {
            return 7002;
        }

        $class = $this->getByAccountOrPhone($params['account']);
        if (!$class) {
            return 7011;
        }

        if (Crypt::decryptString($class->password) !== $params['password']) {
            return 7014;
        }

        try {
            $class->last_login_time = time();

            $res = $class->save();
            if ($res) {
                return $this->dataHandler($class->toArray(), $params['game_id'] ?? 0);
            }
        } catch (\Throwable $th) {
            yqlog($th->getMessage());
            return 9999;
        }

        return -1;
    }

    /**
     * 令牌登录
     */
    public function tokenLogin($params)
    {
        if (!$this->accountVerify($params['account'] ?? '')) {
            return 7001;
        }

        if (!$this->isAccountExisted($params['account'])) {
            return 7011;
        }

        $class = UserAccount::where('account', $params['account'])->first();
        if (!$class) {
            return 7014;
        }

        if (!$this->tokenVerify($params['account'], Crypt::decryptString($class->password), $params['token'] ?? '')) {
            return 7016;
        }

        try {
            $class->last_login_time = time();

            $res = $class->save();
            if ($res) {
                return $this->dataHandler($class->toArray(), $params['game_id'] ?? 0);
            }
        } catch (\Throwable $th) {
            yqlog($th->getMessage());
            return 9999;
        }

        return -1;
    }

    /**
     * 手机绑定
     */
    public function phoneBind($params)
    {
        if (!$this->phoneVerify($params['phone'] ?? '')) {
            return 7004;
        }

        if ($this->isPhoneExisted($params['phone'])) {
            return 6043;
        }

        $verify = $this->codeVerify(PhoneCodeService::PHONE_CODE_TYPE_BIND, $params['phone'], $params['code'] ?? '');
        if ($verify !== true) {
            return $verify;
        }

        if (!$this->isAccountExisted($params['account'] ?? '')) {
            return 7011;
        }

        try {
            $class                  = UserAccount::where('account', $params['account'])->first();
            $class->phone           = $params['phone'];
            $class->phone_bind_time = time();

            $res = $class->save();
            if ($res) {
                return $this->dataHandler($class->toArray());
            }
        } catch (\Throwable $th) {
            yqlog($th->getMessage());
            return 9999;
        }

        return -1;
    }

    /**
     * 手机解绑
     */
    public function phoneUnbind($params)
    {
        if (!$this->phoneVerify($params['phone'] ?? '')) {
            return 7004;
        }

        if (!$this->isPhoneExisted($params['phone'])) {
            return 7013;
        }

        $verify = $this->codeVerify(PhoneCodeService::PHONE_CODE_TYPE_UNBIND, $params['phone'], $params['code'] ?? '');
        if ($verify !== true) {
            return $verify;
        }

        if (!$this->isAccountExisted($params['account'] ?? '')) {
            return 7011;
        }

        try {
            $class                  = UserAccount::where('account', $params['account'])->first();
            $class->phone           = '';
            $class->phone_bind_time = 0;

            $res = $class->save();
            if ($res) {
                return $this->dataHandler($class->toArray());
            }
        } catch (\Throwable $th) {
            yqlog($th->getMessage());
            return 9999;
        }

        return -1;
    }

    /**
     * 实名认证
     */
    public function idcardAuthenticate($params)
    {
        if (!$this->nameVerify($params['name'] ?? '')) {
            return 7015;
        }

        if (!$this->idcardVerify($params['idcard'] ?? '')) {
            return 7009;
        }

        if (!$this->isAccountExisted($params['account'] ?? '')) {
            return 7011;
        }

        $one = UserAccount::where('idcard', $params['idcard'])->where('name', $params['name'])->first();
        if (!$one) {
            $res = IdcardAuthService::getInstance()->check($params['name'], $params['idcard']);
            if (!$res) {
                return 7010;
            }
        }

        try {
            $class                     = UserAccount::where('account', $params['account'])->first();
            $class->name               = $params['name'];
            $class->idcard             = $params['idcard'];
            $class->authenticate_time  = time();

            $res = $class->save();
            if ($res) {
                return $this->dataHandler($class->toArray());
            }
        } catch (\Throwable $th) {
            yqlog($th->getMessage());
            return 9999;
        }

        return -1;
    }

    /**
     * 找回密码
     */
    public function passwordRetrieve($params)
    {
        if (!$this->phoneVerify($params['phone'] ?? '')) {
            return 7004;
        }

        if (!$this->passwordVerify($params['password'] ?? '')) {
            return 7002;
        }

        $verify = $this->codeVerify(PhoneCodeService::PHONE_CODE_TYPE_RETRIEVE, $params['phone'], $params['code'] ?? '');
        if ($verify !== true) {
            return $verify;
        }

        if (!$this->isPhoneExisted($params['phone'])) {
            return 7013;
        }

        try {
            $class           = UserAccount::where('phone', $params['phone'])->first();
            $class->password = Crypt::encryptString($params['password']);

            $res = $class->save();
            if ($res) {
                return $this->dataHandler($class->toArray());
            }
        } catch (\Throwable $th) {
            yqlog($th->getMessage());
            return 9999;
        }

        return -1;
    }

    /**
     * 数据整合
     */
    public function dataHandler($params, $game_id = 0)
    {
        $params['token'] = $this->tokenGenerate($params['account'], Crypt::decryptString($params['password']));
        unset($params['password']);

        if ($game_id) {
            $params['sign'] = $this->signGenerate($params, $game_id);
        }

        return $params;
    }

    /**
     * 生成签名
     */
    public function signGenerate($params, $game_id)
    {
        $game = Games::where('game_id', $game_id)->first();
        if (!$game) {
            return 6030;
        }

        $data = [
            'token'   => $params['token'],
            'user_id' => $params['openid'],
            'time'    => $params['last_login_time'],
        ];

        return SdkService::getInstance()->getSign($game->appkey, $data);
    }

    /**
     * 判断账号是否存在
     */
    public function isAccountExisted($account)
    {
        $class = UserAccount::where('account', $account)->first();
        if ($class) {
            return true;
        }

        return false;
    }

    /**
     * 判断手机号是否存在
     */
    public function isPhoneExisted($phone)
    {
        $class = UserAccount::where('phone', $phone)->first();
        if ($class) {
            return true;
        }

        return false;
    }

    /**
     * 校验账号是否合法
     */
    public function accountVerify($account)
    {
        $lenth = strlen($account);
        if (!$account || $lenth < 6 || $lenth > 12) {
            return false;
        }

        $pattern = '/^[a-zA-Z0-9]+$/';
        if (!preg_match($pattern, $account)) {
            return false;
        }

        return true;
    }

    /**
     * 校验密码是否合法
     */
    public function passwordVerify($password)
    {
        $lenth = strlen($password);
        if (!$password || $lenth < 6 || $lenth > 12) {
            return false;
        }

        $pattern = '/^[a-zA-Z0-9]+$/';
        if (!preg_match($pattern, $password)) {
            return false;
        }

        return true;
    }

    /**
     * 生成Token
     */
    public function tokenGenerate($account, $password)
    {
        return md5($account . $password . 'XIPINQILE');
    }

    /**
     * 校验Token
     */
    public function tokenVerify($account, $password, $token)
    {
        return $token == $this->tokenGenerate($account, $password);
    }

    /**
     * 校验手机号是否合法
     */
    public function phoneVerify($phone)
    {
        $pattern = '/^1[3456789]\d{9}$/';
        if (!preg_match($pattern, $phone)) {
            return false;
        }

        return true;
    }

    /**
     * 校验验证码
     */
    public function codeVerify($type, $phone, $code)
    {
        $res = PhoneCodeService::getInstance()->verify($type, $phone, $code);
        if ($res !== true) {
            return $res;
        }

        return true;
    }

    /**
     * 校验身份证姓名是否合法
     */
    public function nameVerify($name)
    {
        if (mb_strlen($name) < 2) {
            return false;
        }

        // 验证字符串是否包含中文
        if (!preg_match('/[\x{4e00}-\x{9fa5}]/u', $name)) {
            return false;
        }

        return true;
    }

    /**
     * 校验身份证号码是否合法
     */
    public function idcardVerify($idcard)
    {
        $pattern = '/^(\d{17}[\dXx]|\d{15})$/';
        if (!preg_match($pattern, $idcard)) {
            return false;
        }

        if (strlen($idcard) == 18) {
            $idcard = strtoupper($idcard);
            $factor = array(7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2);
            $checkCode = array('1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2');
            $sum = 0;
            for ($i = 0; $i < 17; $i++) {
                $sum += intval($idcard[$i]) * $factor[$i];
            }
            $mod = $sum % 11;
            if ($checkCode[$mod] != $idcard[17]) {
                return false;
            }
        }

        return true;
    }
}
